package com.sl.biz.modular.process.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.google.common.collect.Maps;
import com.sl.auth.core.enums.SaClientTypeEnum;
import com.sl.auth.core.util.StpCompositeUtil;
import com.sl.biz.core.runner.loader.DatabaseProcessPluginLoader;
import com.sl.biz.modular.process.controller.request.ProcessCompObjectRebuildRequest;
import com.sl.biz.modular.process.dao.domain.dto.ProcessCompObjectDTO;
import com.sl.biz.modular.process.dao.domain.dto.ProcessCompVersionBuildDTO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessCompObjectDO;
import com.sl.biz.modular.process.dao.domain.entity.ProcessCompVersionBuildDO;
import com.sl.biz.modular.process.dao.service.ProcessCompObjectDaoService;
import com.sl.biz.modular.process.service.ProcessCompObjectBizService;
import com.sl.biz.modular.process.service.ProcessCompVersionBuildService;
import com.sl.core.domain.dto.SquareLakeLayout;
import com.sl.core.utils.JsonUtil;
import com.sl.core.engine.ProcessEngine;
import com.sl.core.engine.plugin.ProcessPluginRegistry;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;


@Service
@RequiredArgsConstructor
public class ProcessCompObjectBizServiceImpl implements ProcessCompObjectBizService {

    private final ProcessCompObjectDaoService compObjectDaoService;

    private final ProcessCompVersionBuildService buildService;

    @Value("${square.component.build.settingPath:}")
    private String setting;


    @Override
    public Boolean save(ProcessCompObjectDO processComp) {
        //先查询一把
        ProcessCompObjectDTO processCompObjectDTO = compObjectDaoService.queryByCodeAndVersion(StpCompositeUtil.getOrgId(), processComp.getCompCode(), processComp.getCompVersion());
        if (ObjectUtil.isNotNull(processCompObjectDTO)) {
            processComp.setId(processCompObjectDTO.getId());
            compObjectDaoService.updateById(processComp);
        } else {
            compObjectDaoService.save(processComp);
        }
        //删除状态
        buildService.removeByCodeAndVersion(processComp.getCompCode(),processComp.getCompVersion());
        return Boolean.TRUE;
    }


    @Override
    public ProcessCompObjectDTO getByCodeAndVersion(String compCode, String compVersion) {
        ProcessCompObjectDTO processCompObjectDTO = compObjectDaoService.queryByCodeAndVersion(StpCompositeUtil.getOrgId(), compCode, compVersion);

        return processCompObjectDTO;
    }

    @Override
    public Boolean saveAndRebuild(ProcessCompObjectRebuildRequest processComp) {

        String compFile = processComp.getCompFile();

        //先解压下来处理一把
        String compCode = processComp.getCompCode();
        String compVersion = processComp.getCompVersion();
        //获取最近一次是否还在构建，如果还在则直接返回

        ProcessCompVersionBuildDO processCompVersionBuildDO = new ProcessCompVersionBuildDO();
        processCompVersionBuildDO.setCompCode(compCode);
        processCompVersionBuildDO.setCompVersion(compVersion);
        ProcessCompVersionBuildDTO processCompVersionBuildDTO = buildService.getLastCodeAndVersion(processCompVersionBuildDO);
        if (ObjectUtil.isNotNull(processCompVersionBuildDTO) && ObjectUtil.equals(processCompVersionBuildDTO.getBuildStatus(), 1)) {
            Assert.isFalse(true, "正在构建中....");
        }

        String pluginId = ProcessPluginRegistry.getId(StpCompositeUtil.getOrgId(), compCode, compVersion);


        //构建之前需要删除一把
        File temp = new File("temp" + File.separator + "plugin" + File.separator + pluginId);
        FileUtil.del(temp);

        File unzip = DatabaseProcessPluginLoader.file(compFile, "temp" + File.separator, pluginId);

        File file = FileUtil.file(unzip, File.separator + "source");
        List<File> files = FileUtil.loopFiles(file, 1, v -> true);
        if (CollUtil.isEmpty(files)) {
            return Boolean.FALSE;
        }

        File file2 = files.get(0);
        //这里需要重新构建
        SquareLakeLayout transformation = SquareLakeLayout.basic("maven构建", "maven构建");
        Map<String, Object> map = new HashMap<>();
        map.put("buildPath", file2.getAbsolutePath());
        map.put("cmd", "package");
        map.put("setting", setting);
        transformation.getTransformation().addStep("MavenCompile", "MavenCompile", map);
        transformation.getTransformation().addStep("JsonOutput", "JsonOutput", map);
        transformation.getTransformation().addHop("MavenCompile", "JsonOutput");

        String s = transformation.toXml();

        String orgId = StpCompositeUtil.getOrgId();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(s.getBytes(Charset.defaultCharset()));

        SaClientTypeEnum saClientTypeEnum = StpCompositeUtil.get();

        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();


        Map<String, Object> variableMap = Maps.newHashMap();
        variableMap.put("tid", processComp.getTid());
        variableMap.put("openId", processComp.getId());
        CompletableFuture.runAsync(() -> {
            //登陆信息透出
            StpCompositeUtil.appendLogin(saClientTypeEnum, servletRequestAttributes);

            IgnoreStrategy ignoreStrategy = IgnoreStrategy.builder().tenantLine(true).build();
            InterceptorIgnoreHelper.handle(ignoreStrategy);
            Object execute = null;
            //更改状态为构建中
            ProcessCompVersionBuildDO buildDO = new ProcessCompVersionBuildDO();
            buildDO.setCompCode(compCode);
            buildDO.setCompVersion(compVersion);
            buildDO.setRunnerId(IdUtil.fastSimpleUUID());
            buildDO.setBuildStatus(1);
            buildDO.setBuildStartDate(DateUtil.date());
            buildDO.setCreateTime(DateUtil.date());
            buildDO.setOrgId(orgId);
            buildDO.setModifyTime(DateUtil.date());
            buildService.save(buildDO);
            try {
                execute = ProcessEngine.INSTANCE.execute(byteArrayInputStream, map,variableMap);
            } catch (Exception e) {
                //报错了
                execute = "BUILD FAILURE==>" + ExceptionUtil.stacktraceToString(e);
            }
            String str = JsonUtil.toStr(execute);

            //构建成功
            if (StrUtil.containsAnyIgnoreCase(str, "BUILD SUCCESS")) {
                buildDO.setBuildStatus(2);
                //构建成功了，需要把zip拿到重新压缩
                File file1 = FileUtil.file(file2, "target");
                List<File> files1 = FileUtil.loopFiles(file1, 1, (v) -> {
                    String suffix = FileUtil.getSuffix(v);
                    if (StrUtil.equals(suffix, "zip")) {
                        return true;
                    }
                    return false;
                });
                if (CollUtil.isNotEmpty(files1)) {
                    File file3 = files1.get(0);
                    String encode = Base64.encode(file3);
                    processComp.setCompFile(DatabaseProcessPluginLoader.BASE_PREFIX.get(0) + encode);
                }
            } else {
                buildDO.setBuildStatus(3);
            }
            buildDO.setBuildContent(str);
            buildDO.setBuildEndDate(DateUtil.date());
            buildService.updateById(buildDO);
            //构建完成需要删除一把
            File tt = new File("temp" + File.separator + "plugin" + File.separator + pluginId);
            FileUtil.del(tt);
            //如果是构建完成 ，需要修改
            if (buildDO.getBuildStatus().equals(2)) {
                this.save(processComp);
            }
            RequestContextHolder.resetRequestAttributes();
            StpCompositeUtil.clear();
        });
        return Boolean.TRUE;
    }

    @Override
    public Boolean rebuild(ProcessCompObjectRebuildRequest processComp) {
        ProcessCompObjectDTO byId = this.compObjectDaoService.queryByCodeAndVersion(processComp.getCompCode(), processComp.getCompVersion());
        processComp.setCompFile(byId.getCompFile());
        processComp.setId(byId.getId());
        return saveAndRebuild(processComp);
    }

    @Override
    public void removeByCompCodeAndVersion(ProcessCompObjectDO processCompObjectDO) {
        this.compObjectDaoService.removeByCompCodeAndVersion(
                processCompObjectDO.getCompCode(),
                processCompObjectDO.getCompVersion()
        );
    }
}
